package com.lyy.util;

import com.lyy.constant.JwtConst;
import lombok.SneakyThrows;

import java.util.*;

import cn.hutool.core.util.ObjectUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
/**
 * @author Liangyaoyun
 */
public class JwtUtil {
    /**
     * 生成用户对应的token字符串，默认将用户的主键，昵称和头像地址添加到token负载中
     *
     * @param id       用户的主键
     * @param nickname 用户的昵称
     * @param avatar   用户的头像
     * @return token字符串
     */
    public static String build(Long id, String nickname, String avatar) {
        if (ObjectUtil.hasNull(id, nickname, avatar)) {
            throw new RuntimeException("必要参数为空");
        }
        JWTCreator.Builder builder = JWT.create();
        builder.withClaim("id", id);
        builder.withClaim("nickname", nickname);
        builder.withClaim("avatar", avatar);
        builder.withSubject(JwtConst.SUBJECT);
        builder.withIssuer(JwtConst.ISSUER);
        builder.withIssuedAt(new Date());
        builder.withExpiresAt(new Date(System.currentTimeMillis() + JwtConst.EXPIRE_TIME));
        return builder.sign(Algorithm.HMAC256(JwtConst.SECRET_KEY));
    }

    /**
     * 验证token字符串，验证失败直接抛出异常，
     * 验证成功后判断当前token是否即将过期，若是则生成新的token并返回，否则返回原token值
     *
     * @param token token字符串
     * @return token信息，若expireSoon为true，表示token即将过期，反之表示token不需要刷新
     */
    @SneakyThrows
    public static Map<String, Object> verify(String token) {

        // 检查必要参数
        if (ObjectUtil.isEmpty(token)) {
            throw new RuntimeException("token字符串为空");
        }

        Map<String, Object> resultMap = new HashMap<>(4);

        // 通过秘钥验证token字符串，验证失败直接抛出异常
        DecodedJWT decodedJwt = JWT.require(Algorithm.HMAC256(JwtConst.SECRET_KEY))
                .build()
                .verify(token);

        // 获取用户信息
        Long id = decodedJwt.getClaim("id").asLong();
        String nickname = decodedJwt.getClaim("nickname").asString();
        String avatar = decodedJwt.getClaim("avatar").asString();

        // 若token过期时间小于指定阈值，则重新生成token并返回
        if (decodedJwt.getExpiresAt().getTime() - System.currentTimeMillis()
                < JwtConst.EXPIRATION_TIME_THRESHOLD) {

            resultMap.put(JwtConst.EXPIRATION_KEY, true);
            resultMap.put(JwtConst.NEW_TOKEN_KEY, build(id, nickname, avatar));
        }
        // 若token过期时间大于指定阈值，不需要重新生成token，将用户信息存入resultMap中返回即可
        else {
            resultMap.put("id", id);
            resultMap.put("nickname", nickname);
            resultMap.put("avatar", avatar);
            resultMap.put(JwtConst.EXPIRATION_KEY, false);
        }
        return resultMap;
    }
}
